package com.aps.demo;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * 订单类
 * 
 * 在APS排程系统中，订单是排产的基本单位。
 * 每个订单包含多个需要按顺序执行的工序，代表一个完整的生产任务。
 * 
 * 业务场景：
 * - 订单J1：生产20个零件A，需要经过车削、铣削、磨削三道工序
 * - 订单J2：生产10个零件B，需要经过车削、铣削两道工序
 * - 每个订单都有明确的开始时间和交付期限
 * 
 * @author APS System
 * @version 1.0
 */
public class Order {
    
    /** 时间格式化器 */
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    
    /** 订单唯一标识符 */
    private String id;
    
    /** 订单数量（要生产的产品数量） */
    private int quantity;
    
    /** 订单开始时间（可以开始生产的最早时间） */
    private LocalDateTime startDate;
    
    /** 订单交付日期（客户要求的完成时间） */
    private LocalDateTime dueDate;
    
    /** 该订单包含的所有工序列表（按工序顺序排列） */
    private List<Operation> operations;
    
    /**
     * 构造函数
     * 
     * @param id 订单ID
     * @param quantity 订单数量
     * @param startDate 开始时间
     * @param dueDate 交付日期
     */
    public Order(String id, int quantity, LocalDateTime startDate, LocalDateTime dueDate) {
        if (quantity <= 0) {
            throw new IllegalArgumentException("订单数量必须大于0");
        }
        if (startDate.isAfter(dueDate)) {
            throw new IllegalArgumentException("开始时间不能晚于交付时间");
        }
        
        this.id = id;
        this.quantity = quantity;
        this.startDate = startDate;
        this.dueDate = dueDate;
        this.operations = new ArrayList<>();
    }
    
    /**
     * 向订单添加工序
     * 
     * 工序会按照添加顺序进行排列，代表生产流程中的执行顺序。
     * 
     * @param operation 要添加的工序
     */
    public void addOperation(Operation operation) {
        if (operation == null) {
            throw new IllegalArgumentException("工序不能为空");
        }
        if (!operation.getOrder().getId().equals(this.id)) {
            throw new IllegalArgumentException("工序所属订单与当前订单不匹配");
        }
        this.operations.add(operation);
    }

    /**
     * 获取指定工序的下一工序
     * @param current 当前工序
     * @return 下一工序，如无则返回null
     */
    public Operation getNextOperation(Operation current) {
        int currentSeq = current.getSequence();
        for (Operation op : operations) {
            if (op.getSequence() == currentSeq + 1) {
                return op;
            }
        }
        return null;
    }
    
    /**
     * 根据工序顺序号获取工序
     * 
     * @param sequence 工序顺序号
     * @return 对应的工序，如果不存在返回null
     */
    public Operation getOperationBySequence(int sequence) {
        return operations.stream()
                .filter(op -> op.getSequence() == sequence)
                .findFirst()
                .orElse(null);
    }
    
    /**
     * 获取最后一道工序
     * 
     * @return 最后一道工序，如果没有工序返回null
     */
    public Operation getLastOperation() {
        if (operations.isEmpty()) {
            return null;
        }
        return operations.get(operations.size() - 1);
    }
    
    /**
     * 计算订单的总加工时间（所有工序的总时间）
     * 
     * @return 总加工时间（分钟）
     */
    public int getTotalProcessingTime() {
        return operations.stream()
                .mapToInt(Operation::getTotalProcessingTime)
                .sum();
    }
    
    /**
     * 计算订单可用的总时间（从开始时间到交付时间）
     * 
     * @return 可用总时间（分钟）
     */
    public long getAvailableTimeInMinutes() {
        return java.time.Duration.between(startDate, dueDate).toMinutes();
    }
    
    /**
     * 检查订单是否可以在规定时间内完成
     * 
     * @return 如果总加工时间不超过可用时间返回true，否则返回false
     */
    public boolean isFeasible() {
        return getTotalProcessingTime() <= getAvailableTimeInMinutes();
    }
    
    // Getter和Setter方法
    
    /**
     * 获取订单ID
     * 
     * @return 订单ID
     */
    public String getId() {
        return id;
    }
    
    /**
     * 设置订单ID
     * 
     * @param id 订单ID
     */
    public void setId(String id) {
        this.id = id;
    }
    
    /**
     * 获取订单数量
     * 
     * @return 订单数量
     */
    public int getQuantity() {
        return quantity;
    }
    
    /**
     * 设置订单数量
     * 
     * @param quantity 订单数量
     */
    public void setQuantity(int quantity) {
        if (quantity <= 0) {
            throw new IllegalArgumentException("订单数量必须大于0");
        }
        this.quantity = quantity;
        // 更新所有工序的总加工时间
        for (Operation operation : operations) {
            operation.updateTotalProcessingTime();
        }
    }
    
    /**
     * 获取开始时间
     * 
     * @return 开始时间
     */
    public LocalDateTime getStartDate() {
        return startDate;
    }
    
    /**
     * 设置开始时间
     * 
     * @param startDate 开始时间
     */
    public void setStartDate(LocalDateTime startDate) {
        if (startDate.isAfter(this.dueDate)) {
            throw new IllegalArgumentException("开始时间不能晚于交付时间");
        }
        this.startDate = startDate;
    }
    
    /**
     * 获取交付日期
     * 
     * @return 交付日期
     */
    public LocalDateTime getDueDate() {
        return dueDate;
    }
    
    /**
     * 设置交付日期
     * 
     * @param dueDate 交付日期
     */
    public void setDueDate(LocalDateTime dueDate) {
        if (this.startDate.isAfter(dueDate)) {
            throw new IllegalArgumentException("开始时间不能晚于交付时间");
        }
        this.dueDate = dueDate;
    }
    
    /**
     * 获取工序列表
     * 
     * @return 工序列表
     */
    public List<Operation> getOperations() {
        return operations;
    }
    
    /**
     * 设置工序列表
     * 
     * @param operations 工序列表
     */
    public void setOperations(List<Operation> operations) {
        this.operations = operations != null ? operations : new ArrayList<>();
    }
    
    /**
     * toString方法，便于调试和日志输出
     * 
     * @return 格式化的字符串表示
     */
    @Override
    public String toString() {
        return String.format("订单[%s]: 数量=%d个, 开始=%s, 交付=%s, 工序数=%d, 总时间=%d分钟", 
                id, 
                quantity, 
                startDate.format(formatter), 
                dueDate.format(formatter),
                operations.size(),
                getTotalProcessingTime());
    }
    
    /**
     * equals方法，基于订单ID进行比较
     * 
     * @param obj 要比较的对象
     * @return 如果订单ID相同返回true，否则返回false
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        
        Order order = (Order) obj;
        return id != null ? id.equals(order.id) : order.id == null;
    }
    
    /**
     * hashCode方法，基于订单ID
     * 
     * @return 散列值
     */
    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }
}
